package file

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"

	"archive/zip"

	"gitee.com/ispace/core/infrastructure/common/dto"
	"gitee.com/ispace/core/infrastructure/common/gv"
)

type FileCompressionHandler struct {
	request dto.WsRequestDto
}

type Params struct {
	SourcePath string `json:"sourcePath"`
	SourceType string `json:"sourceType"` // "file" | "folder"
	IsVolume   bool   `json:"isVolume"`
	VolumeSize int64  `json:"volumeSize"` // 默认1GB
	TargetPath string `json:"targetPath"`
	TargetName string `json:"targetName"`
}

// Init 方法实现
func (h *FileCompressionHandler) Init(request dto.WsRequestDto) {
	h.request = request
}

// Execute 方法实现
func (h *FileCompressionHandler) Execute() dto.WsResponseDto {

	// step init:
	result := dto.WsResponseDto{}
	result.Header.Id = h.request.Header.Id

	// step 1: params
	bodyBytes, err := json.Marshal(h.request.Body)
	if err != nil {
		result.Header.Stat = 2
		result.Body = fmt.Sprintf("Error marshalling message:%s", err)
		return result
	}

	params := Params{}
	err = json.Unmarshal(bodyBytes, &params)
	if err != nil {
		result.Header.Stat = 2
		result.Body = fmt.Sprintf("Error unmarshalling message:%s", err)
		return result
	}

	// step 2:
	list, err2 := h.compressionV2(params)
	if err2 != nil {
		result.Header.Stat = 2
		result.Body = fmt.Sprintf("Error compression message:%s", err)
		return result
	}
	// step end:
	result.Header.Stat = 200
	result.Body = list
	return result
}

func (ic *FileCompressionHandler) compression(params Params) ([]string, error) {
	// 设置默认参数

	if params.VolumeSize == 0 {
		params.VolumeSize = 1024 * 1024 * 1024 // 1GB
	}
	if params.TargetPath == "" {
		params.TargetPath = params.SourcePath
	}
	if params.TargetName == "" {
		params.TargetName = filepath.Base(params.SourcePath)
	}

	// 获取所有文件
	params.SourcePath = path.Join(gv.BasePath, params.SourcePath)
	params.TargetPath = path.Join(gv.BasePath, params.TargetPath)
	var files []string
	if params.SourceType == "folder" {
		err := filepath.Walk(params.SourcePath, func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}
			if !info.IsDir() {
				files = append(files, path)
			}
			return nil
		})
		if err != nil {
			return nil, err
		}
	} else {
		files = []string{params.SourcePath}
	}

	// 分卷压缩
	var results []string
	partNum := 1
	var currentWriter *zip.Writer
	var currentFile *os.File
	currentSize := int64(0)

	for _, filePath := range files {
		file, err := os.Open(filePath)
		if err != nil {
			return nil, fmt.Errorf("打开文件失败: %v", err)
		}
		defer file.Close()

		info, err := file.Stat()
		if err != nil {
			return nil, fmt.Errorf("获取文件信息失败: %v", err)
		}

		// 检查分卷
		if currentWriter == nil || currentSize+info.Size() > params.VolumeSize {
			if currentWriter != nil {
				currentWriter.Close()
				currentFile.Close()
			}

			partName := fmt.Sprintf("%s_part%02d.zip", params.TargetName, partNum)
			var targetDir = path.Dir(params.TargetPath)
			targetPath := filepath.Join(targetDir, partName)
			currentFile, err = os.Create(targetPath)
			if err != nil {
				return nil, fmt.Errorf("创建分卷文件失败: %v", err)
			}

			currentWriter = zip.NewWriter(currentFile)
			currentSize = 0
			partNum++
			results = append(results, strings.TrimPrefix(targetPath, gv.BasePath))
		}

		// 添加文件到ZIP
		relPath, err := filepath.Rel(params.SourcePath, filePath)
		if err != nil {
			return nil, fmt.Errorf("获取相对路径失败: %v", err)
		}

		header, err := zip.FileInfoHeader(info)
		if err != nil {
			return nil, fmt.Errorf("创建ZIP头失败: %v", err)
		}
		header.Name = filepath.ToSlash(relPath)

		writer, err := currentWriter.CreateHeader(header)
		if err != nil {
			return nil, fmt.Errorf("创建ZIP条目失败: %v", err)
		}

		if _, err := io.Copy(writer, file); err != nil {
			return nil, fmt.Errorf("写入文件内容失败: %v", err)
		}

		currentSize += info.Size()
	}

	if currentWriter != nil {
		currentWriter.Close()
		currentFile.Close()
	}

	return results, nil
}

// createZipVolumes 创建分卷压缩文件并返回文件列表
func createZipVolumes(source, outputPrefix string, volumeSize int64) ([]string, error) {

	// 删除旧文件（支持分卷）
	oldFiles, _ := filepath.Glob(outputPrefix + ".zip.*")
	for _, f := range oldFiles {
		if err := os.Remove(f); err != nil {
			log.Printf("警告: 无法删除旧文件 %s: %v", f, err)
		}
	}

	// 构建命令（示例：7z a -v1G archive.zip ./large_folder）
	cmd := exec.Command(
		"7z",
		"a",
		"-aoa",
		"-mx=1",
		"-mmt=12",
		"-v"+fmt.Sprintf("%db", volumeSize),
		"-tzip",
		outputPrefix+".zip",
		source,
	)

	output, err := cmd.CombinedOutput() // 捕获 Stdout + Stderr
	if err != nil {
		return nil, fmt.Errorf("7z 执行失败: %v, 输出: %s", err, string(output))
	}

	// 获取生成的分卷文件列表
	var files []string
	baseName := filepath.Base(outputPrefix)
	dir := filepath.Dir(outputPrefix)

	// 遍历输出目录，匹配分卷文件（如 archive.zip.001, archive.zip.002...）
	err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !info.IsDir() && strings.HasPrefix(filepath.Base(path), baseName+".zip") {
			files = append(files, strings.TrimPrefix(path, gv.BasePath))
		}
		return nil
	})

	return files, err
}

func (ic *FileCompressionHandler) compressionV2(params Params) ([]string, error) {
	// 设置默认参数
	if params.VolumeSize == 0 {
		params.VolumeSize = 1024 * 1024 * 1024 // 1GB
	}
	if params.TargetPath == "" {
		params.TargetPath = params.SourcePath
	}
	if params.TargetName == "" {
		params.TargetName = filepath.Base(params.SourcePath)
	}

	// 获取所有文件
	params.SourcePath = path.Join(gv.BasePath, params.SourcePath)
	params.TargetPath = path.Join(gv.BasePath, params.TargetPath)

	// step core:
	outputPrefix := params.TargetPath
	files, err := createZipVolumes(params.SourcePath, outputPrefix, params.VolumeSize)
	if err != nil {
		return nil, err
	}
	return files, nil

}
